module Visualizer::VisualisationTreeADT

import List;
import IO;
import Number;
import String;

/* 	Module defines a datatype that represents a java structure
	for the visualisation.
	
	The choice has been made for a strongly typed tree so
	parsing it and using it for visulasation is easier.
	
*/

// Data type for Java methods
data Method = method(str name, loc location, int unitSize, int cc);
// Data type for Java classes
data Class = class(str name, loc location, int moduleSize,  list[Method] methods);
// Data type for Java packages
data VisualisationTree = package( str name, list[VisualisationTree] packages, list[Class] classes);


// Calculate the agregeated metric totals needed for the visualisation for a package
public tuple[int totalModuleSize, int amountSubPackages, int amountClasses, int totalCyclomaticComplexity] calculateAgregatedMetrics(VisualisationTree tr){
   int totalModuleSize = 0;
   int amountSubPackages = 0;
   int amountClasses = 0;
   int totalCyclomaticComplexity = 0;
   visit(tr) {
     case package( _, _, _) : 
     	{
			amountSubPackages = amountSubPackages + 1;
		}
     case class(_, _, int moduleSize,  _): 
     	{
     		totalModuleSize = totalModuleSize + moduleSize;
     		amountClasses = amountClasses +1;
     	}
     case method(_, _, _, int cc): 
	     {
	     	totalCyclomaticComplexity = totalCyclomaticComplexity + cc;
	     }
   };
   return <totalModuleSize, amountSubPackages, amountClasses, totalCyclomaticComplexity>;
}

// Creates a list of classes that represent the 10 larges classe in the tree.
public list[Class] getTopTenGod(VisualisationTree tree){

  list[Class] tmp = [];
  
  visit(tree){
    case class(str name, loc location, int moduleSize,  list[Method] methods): {
          tmp = tmp + [class(name, location, moduleSize, methods)];
        }
  }
  
  // if no classes found in the package, empty package. So return no classes
  if (isEmpty(tmp)) {
    return [];
  }
  
  list[Class] x = [];
  list[Class] buf = [];
  bool inputted = false;
  for( i <- [0..(size(tmp)-1)] ) {
    buf = [];
    inputted = false;
    if( isEmpty(x) ) {
    	x = [tmp[i]];
    }
    else {
	    for( j <- [0..(size(x)-1)] ){
	      if( x[j].moduleSize <= tmp[i].moduleSize && inputted == false ){
	        buf = buf + [tmp[i], x[j]];
	        inputted = true;
	      }
	      else{ buf = buf + [x[j]]; }
	    }
	    
	    if( inputted == false ) {  buf = buf + [tmp[i]]; }
	    x = buf;
	    
	    if( size(x) > 10 )
	    { // the head of the list contains the biggest classes. We only need the top
	      // ten so throw away the rest, unwanted clutter
	      x = head(x, 10);
	    }
    }
  }
  
  return x;
}

public list[Method] getTopTenCC(VisualisationTree t)
{
  list[Method] tmp = [];
  list[Method] x = [];
  
  visit(t){
    case method(str name, loc location, int unitSize, int cc):{
        tmp = tmp + [method(name, location, unitSize, cc)];
      }
  }
  
  // if tmp is empty return empty set
  if (isEmpty(tmp)){
    return [];
  }

  list[Method] buf = [];
  bool inputted = false;
  for( i <- [0..(size(tmp)-1)] ) {
    buf = [];
    inputted = false;
    if( isEmpty(x) ){
    	x = [tmp[i]];
    }
    else{
	    for( j <- [0..(size(x)-1)] ){
	      if( x[j].cc <= tmp[i].cc && inputted == false ) {
	        buf = buf + [tmp[i], x[j]];
	        inputted = true;
	      }
	      else { buf = buf + [x[j]]; }
	    }
	    
	    if( inputted == false ) { buf = buf + [tmp[i]]; }
	    x = buf;
	    
	    if( size(x) > 10 )
	    { // the head of the list contains the biggest classes. We only need the top
	      // ten so throw away the rest, unwanted clutter
	      x = head(x, 10);
	    }
    }
  }
  
  return x;
}

// Prints a list of mehtods
public void printMethodList(list[Method] x)
{
  for( i <- [0..(size(x)-1)] )
  {
    print(x[i].name, x[i].cc);
  }
}

// Prints a list of classes
public void printClassList(list[Class] x)
{
  for( i <- [0..(size(x)-1)] )
  {
    print(x[i].name, x[i].moduleSize);
  }
}

// Generic print function
private void print(str name, int n)
{
  str whitespace = "                                                            "; // whitespace 60 length
  println(name + substring(whitespace, 0, 60-size(name)) + toString(n));
}